跳到主要内容

Go 语言学习-包管理

Golang 的包管理

每一个 Go 语言程序都必须是一些包的一部分。一个独立 可执行的 Go 语言程序必须有 package main 声明。如果一个程序是 main 包的一部分,那么在 go install 则会生成一个二进制文件,在执行时则会调用 main 函数。

go install 命令在编译源代码之后还安装到指定的目录,即:go build 命令 + 把编译后的可执行文件放到 GOPATH/bin 目录下

如果一个程序除了 main 包外还是其他包的一部分,那么在使用 go install 命令时会创建包存档文件。

配置环境

Linux 配置环境变量

$ vim ~/.bashrc

# 设置语言路径
export GOROOT=/usr/local/go # 表示源码包路径
export GOPATH=$HOME/go # 开发者 Go 的项目默认路径,一般不用
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
$ source ~/.bashrc   # 使配置文件生效

设置下载代理

# 例如这里设置为 C:\Users\33204\go
go env -w GOPATH=我们自己的工作区路径

# 设置代理服务器(在 GitHub 下载工具)
go env -w GO111MODULE=on
# 这个 direct 表示前面的代理找不到则回源地址去找
go env -w GOPROXY=https://goproxy.cn,direct

检查 Go 的环境变量

go env

Go Modules 是什么?

GoMOD 就是 Go 的 Maven,用于管理依赖,go mod 是 Golang 1.11 版本引入的官方包(package)依赖管理工具,用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。

使用起来也非常简单,常用命令就一个 go mod tidy,通俗来说就是将当前的库源码文件所依赖的包,全部安装并记录下来,多的包就删掉,少了的就自动补上

Golang 提供一个环境变量 GO111MODULE 来设置是否使用 mod,它有3个可选值,分别是 off, on, auto(默认值),具体含义如下:

  • off:GOPATH mode,查找 vendor 和 GOPATH 目录
  • on:module-aware mode,即使用 go module,忽略 GOPATH 目录
  • auto:如果当前目录不在 $GOPATH 并且 当前目录(或者父目录)下有 go.mod 文件,则使用 GO111MODULE, 否则仍旧使用 GOPATH mode。

修改 GO111MODULE 的值的语句是:set GO111MODULE=on

在使用模块的时候, GOPATH 是无意义的,不过它还是会把下载的依赖储存在 GOPATH/src/mod 中,也会把 go install 的结果放在 GOPATH/bin(如果 GOBIN 不存在的话)

go.mod 文件

Go.mod 是 Golang1.11 版本新引入的官方包管理工具用于解决之前没有地方记录依赖包具体版本的问题,方便依赖包的管理。(类似于 Java 的 pom.xml 文件)

查看一下 go.mod 文件

go.mod 提供了 module, require、replace 和 exclude 四个命令

  • module 语句指定包的名字(路径)
  • require 语句指定的依赖项模块
  • replace 语句可以替换依赖项模块
  • exclude 语句可以忽略依赖项模块

具体参考 深入Go Module之go.mod文件解析

常用命令

  • go mod download 下载 go.mod 中的模块到本地缓存,缓存路径是 $GOPATH/pkg/mod/cache
  • go mod edit 是提供了命令版编辑 go.mod 的功能,例如 go mod edit -fmt go.mod 会格式化 go.mod
  • go mod graph 把模块之间的依赖图显示出来
  • go mod init 初始化模块(例如把原本 dep 管理的依赖关系转换过来),注意要在 init 后面加上项目名
  • go mod tidy 增加缺失的包,移除没用的包
  • go mod vendor 把依赖拷贝到 vendor/ 目录下
  • go mod verify 确认依赖关系
  • go mod why 解释为什么需要包和模块

显示依赖图可以直接使用 GoLand 提供的工具(就像 IDEA 那样的)

初始化项目

在任意文件夹创建项目


mkdir -p $HOME/als/project_name

指定 module 的根目录并生成 go.mod 文件

go mod init github.com/als/project_name

这将会生成模块配置文件 go.mod,其中包含模块名称和版本。

module github.com/als/project_name

go 1.17

go.mod 文件定义 Module 的根,go 命令将相应地与包一起使用。

添加依赖

其实只需在文件中指明依赖的包,执行时会自动下载依赖

创建 main.go 文件

package main

import (
"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080 (for windows "localhost:8080")
}

执行 go run main.go 运行代码会发现 go mod 会自动查找依赖自动下载

但是!在 go 1.16 版本后,运行 go 命令(go run, go build, go test)时,如果 import 的依赖在 go.mod 文件中没有,不会再自动下载并修改 go.mod 和 go.sum 文件,而会提示错误,并需要手动执行 go get 命令下载对应的包。

go get github.com/gin-gonic/gin

原因是自动修复的方式不是在任何场景下都适用:如果导入的包在没有提供任何依赖的情况自动添加新依赖,则可能会引起公共依赖包的升级等。

添加完包后,可以通过使用 go list -m all 查看当前模块所依赖的包列表。

清理无用的依赖

go mod tidy

使用 vendor

使用 vendor 时如果需要下载依赖,需要临时开启 GO111MODULE

GO111MODULE=on go get github.com/gin-gonic/gin@master
go mod vendor

如果需要使用 vendor 打包则

GO111MODULE=on go run -mod=vendor .

更新依赖

更新依赖为指定版本依赖

运行 go get -u 将会升级到最新的次要版本或者修订版本(x.y.z, z是修订版本号, y是次要版本号) 运行 go get -u=patch 将会升级到最新的修订版本 运行 go get package@version 将会升级到指定的版本号 version 运行 go get 如果有版本的更改,那么 go.mod 文件也会更改

注意这个 -u 是打印下载细节的意思

go list -m -versions rsc.io/sampler

rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99

go get rsc.io/sampler@v1.3.1

编译项目

随便创建一个 main.go 文件

package main

import "fmt"

func main() {
fmt.Println("Hello, World!")
}

运行 go build 构建项目,可以发现生成了 exe 文件

或者执行以下命令直接运行

go run main.go

编写完代码后执行 go mod tidy 会自动下载依赖的库,也会删除多余的库

如果想把项目安装到 GOPATH 里面则需要使用

go install

C 依赖库

编译好的项目丢到 Docker 容器(Alpine 镜像)里面执行时发现报错 not found ld-linux-x86-64.so.2

这是因为 Alpine 镜像缺少了这个 ld-linux-x86-64.so.2 动态链接库,解决方法如下:

mkdir /lib64
ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2

或者直接在 Build 的时候就直接不依赖 C 的动态库链接

CGO_ENABLED=0 go build -o collect

配置私有库

环境变量 GOPRIVATE 用来控制 go 命令把哪些仓库看做是私有的仓库,这样的话,就可以跳过 proxy server 和校验检查,这个变量的值支持用逗号分隔,可以填写多个值,例如:

GOPRIVATE=*.corp.example.com,rsc.io/private

命令行设置:

go env -w GOPRIVATE=private.repo.com

这样 go 命令会把所有包含这个后缀的软件包,包括 git.corp.example.com/xyzzy , rsc.io/private, 和 rsc.io/private/quux 都以私有仓库来对待。

若所有需要配置的私有仓库都存在于一个组织下,如 github 下的组织 org_name,则直接填写组织名即可:

GOPRIVATE=github.com/org_name

如果要更新不支持https协议的私有库,还需再做如下的配置。

go get -insecure,但是很麻烦,每个包都需要手动在 go mod 下导入(go mod 是不支持 HTTP 的); go env -w GOINSECURE=private.repo.com,设置 GOINSECURE 参数,非常方便。仅在 go 1.14 后新加入。

Reference

Getting started with Go 官方文档 Go Modules Reference Go Modules设置私有库,以及支持HTTP的私有库操作 go mod使用 深入Go Module之go.mod文件解析 go mod常用命令 以及 常见问题